package com.member.mp.web.auth;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.member.common.cache.CacheService;
import com.member.common.constant.SystemConst;
import com.member.common.core.domain.R;
import com.member.common.enums.BizUserStatusEnum;
import com.member.common.enums.OrderDeleteEnum;
import com.member.common.enums.ProcessStatusEnum;
import com.member.common.utils.DateUtils;
import com.member.common.utils.SecurityUtils;
import com.member.common.utils.ShortSnowflakeUtils;
import com.member.common.utils.TokenUtils;
import com.member.mp.aop.DistributeLock;
import com.member.mp.config.SmsManager;
import com.member.mp.web.user.SupperController;
import com.member.shop.domain.SysBizTenant;
import com.member.shop.domain.SysBizUser;
import com.member.shop.dto.*;
import com.member.shop.service.ISysBizTenantService;
import com.member.shop.service.ISysBizUserService;
import com.member.system.cache.TokenCache;
import com.member.system.domain.SysConfig;
import com.member.system.service.ISysConfigService;
import io.swagger.annotations.Api;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.util.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ThreadLocalRandom;
import java.util.concurrent.TimeUnit;

/**
 * 【登录接口】控制器
 *
 * @author wangxin
 * @version 1.0
 * @date Mon Jul 03 22:06:51 CST 2024
 **/
@RestController
@Api(value = "登录接口", tags = {"登录接口"})
@RequestMapping("/wx/auth")
public class LoginController extends SupperController {

    private static final Logger log = LoggerFactory.getLogger(LoginController.class);
    @Resource
    private ISysBizUserService sysBizUserService;
    @Resource
    private CacheService cacheService;
    @Resource
    private SmsManager smsManager;
    @Resource
    private ISysConfigService configService;

    private static final String LOGIN_CODE = "LOGIN_";
    private static final String UPDATE_PASSWORD_CODE = "UP_";
    private static final String REGISTER_CODE = "REGISTER_";

    @Resource
    private ISysBizTenantService sysBizTenantService;

    @Autowired
    public RedisTemplate redisTemplate;

    private static final long LOCK_EXPIRE_TIME = 30L; // 锁的有效期，单位秒
    /**
     * 发送注册验证码
     *
     * @return 成功or失败
     */
    @PostMapping("/registerCode/{phoneNum}")
    public R<String> registerCode(@PathVariable("phoneNum") String phoneNum) throws Exception {
        try {
            // 参数校验
            if (StringUtils.isBlank(phoneNum)) {
                return R.fail("手机号不能为空");
            }
            if (!phoneNum.matches("^1[3-9]\\d{9}$")) {
                return R.fail("手机号格式不正确");
            }

            // 生成6位验证码
            String code = String.format("%06d", ThreadLocalRandom.current().nextInt(100000, 1000000));

            // 清除旧验证码
            String cacheKey = REGISTER_CODE + phoneNum;
            if (cacheService.exists(cacheKey)) {
                cacheService.remove(cacheKey);
            }

            // 设置新验证码（包含原子性设置）
            if (cacheService.setNX(cacheKey, code, 300)) { // 5分钟
                // 实际发送短信
                try {
                    smsManager.sendCode(code, phoneNum);
                } catch (Exception e) {
                    cacheService.remove(cacheKey);
                    log.error("短信发送失败: {}", phoneNum, e);
                    return R.fail("短信发送失败，请稍后重试");
                }
                return R.ok();
            }
            return R.fail("请求过于频繁，请稍后再试");
        } catch (Exception e) {
            log.error("验证码发送异常: {}", phoneNum, e);
            return R.fail("系统繁忙，请稍后重试");
        }
    }


    /**
     * 注册用户
     *
     * @param register 注册用户
     * @return 注册结果
     */
    @PostMapping("/registerUser")
    public R<String> registerUser(@RequestBody @Validated RegisterMemberDto register){

        if(!register.getPassword().equals(register.getPassword2())){
            return R.fail("两次登录密码不一致");
        }

        if (!cacheService.exists(REGISTER_CODE + register.getMemberPhone())
                || !register.getRegisterCode().equals(cacheService.get(REGISTER_CODE + register.getMemberPhone()) + "")) {
            return R.fail("验证码错误");
        }

        SysBizUser bizUser = sysBizUserService.getOne(new LambdaQueryWrapper<SysBizUser>().eq(SysBizUser::getUserPhone, register.getMemberPhone()));

        if(bizUser != null){
            return R.fail("您的手机号已被注册");
        }
        SysBizUser sysBizUser = new SysBizUser();
        sysBizUser.setUserPhone(register.getMemberPhone());
        sysBizUser.setPassword(SecurityUtils.encryptPassword(register.getPassword()));
        sysBizUser.setNickName("禾饴"+ RandomStringUtils.randomAlphabetic(8));
        sysBizUser.setIsRegisterMember(0);
        sysBizUser.setDisplayed(BizUserStatusEnum.OK.getKey());
        sysBizUser.setCreateTime(DateUtils.getNowDate());

        List<SysBizTenant> sysBizTenants = sysBizTenantService.selectSysBizTenantList(new LambdaQueryWrapper<SysBizTenant>()
                .eq(SysBizTenant::getDeleted, 0)
                .eq(SysBizTenant::getIsDefault, 1)
                .eq(SysBizTenant::getGrounding, 0));

        if(!CollectionUtils.isEmpty(sysBizTenants)){
            sysBizUser.setTenantId(sysBizTenants.get(0).getId());
        }
        sysBizUser.setScore(0L);
        sysBizUser.setGrade(0L);
        sysBizUser.setIsAdmin(0);
        sysBizUser.setUserRole(1);
        sysBizUser.setUpdateTime(new Date());
        sysBizUser.setDeleted(0);
        sysBizUser.setUseScore(0L);
        sysBizUser.setFrozenScore(0L);
        String token = TokenUtils.createToken();
        sysBizUser.setToken(token);

        sysBizUser.setProcessStatus(ProcessStatusEnum.UN_PROCESS.getKey());
        sysBizUser.setAuthenticationStatus(0);
        sysBizUserService.save(sysBizUser);

        return R.ok();
    }

    /**
     * 发送登录验证码
     *
     * @return
     */
    @PostMapping("/verificationCode/{phoneNum}")
    public R<String> verificationCode(@PathVariable("phoneNum") String phoneNum) throws Exception {
        if (StringUtils.isBlank(phoneNum)) {
            return R.fail("登录手机号不能为空");
        }
        String code = String.format("%6d", 100000 + new Random().nextInt(900000));
        if (cacheService.exists(LOGIN_CODE + phoneNum)) {
            cacheService.remove(phoneNum);
        }
        if (cacheService.setNX(LOGIN_CODE + phoneNum, code, 60 * 5)) {
            smsManager.sendCode(code, phoneNum);
        }
        return R.ok();
    }

    /**
     * 验证码登录（isToSetPassword为true时，跳转到设置密码页面）
     *
     * @return
     */
    @PostMapping("/verificationCode")
    public R<SysBizUser> verificationCode(@RequestBody @Validated VerificationCodeLoginDto verificationCodeLoginDto) {
        if (!cacheService.exists(LOGIN_CODE + verificationCodeLoginDto.getPhoneNumber()) || !verificationCodeLoginDto.getVerificationCode().equals(cacheService.get(LOGIN_CODE + verificationCodeLoginDto.getPhoneNumber()) + "")) {
            return R.fail("验证码错误");
        }
        String phoneNumber = verificationCodeLoginDto.getPhoneNumber();
        String lockKey = "LOGIN:PHONE:" + phoneNumber;
        // 尝试获取锁
        Boolean isLocked = redisTemplate.opsForValue().setIfAbsent(lockKey, "locked", LOCK_EXPIRE_TIME, TimeUnit.SECONDS);
        if (Boolean.FALSE.equals(isLocked)) {
            return R.fail("正在加载，请勿重复点击");
        }
        try {
            SysBizUser sysBizUser = sysBizUserService.verificationCode(verificationCodeLoginDto);
            return R.ok(sysBizUser);
        } finally {
            // 释放锁
            redisTemplate.delete(lockKey);
        }
    }

    /**
     * 设置密码，需要携带token调，会返回新token
     *
     * @return
     */
    @PostMapping("/setPassword/{password}")
    public R<SysBizUser> setPassword(@PathVariable String password) {
        if (StringUtils.isBlank(password)) {
            return R.fail("密码不能为空");
        }
        if (getLoginUser() == null) {
            return R.fail("参数错误");
        }
        SysBizUser sysBizUser = sysBizUserService.getById(getUserId());
        sysBizUser.setPassword(SecurityUtils.encryptPassword(password));
        sysBizUserService.updateById(sysBizUser);
        String token = TokenUtils.createToken();
        TokenCache.setMpData(token, JSON.toJSONString(sysBizUser));
        sysBizUser.setToken(token);
        return R.ok(sysBizUser);
    }

    /**
     * 获取app版本信息
     *
     * @return
     */
    @GetMapping("/appVersion")
    public R<AppVersionDto> appVersion() {
        SysConfig sysConfig = new SysConfig();
        sysConfig.setConfigKey("app");
        List<SysConfig> list = configService.selectConfigList(sysConfig);
        AppVersionDto appVersionDto = new AppVersionDto();
        for (SysConfig config : list) {
            try {
                if (SystemConst.APP_IOS_APPLEID.equals(config.getConfigKey())) {
                    appVersionDto.setAppleId(config.getConfigValue());
                }
                if (SystemConst.APP_IOS_VERSION.equals(config.getConfigKey())) {
                    appVersionDto.setIosVersion(config.getConfigValue());
                }
                if (SystemConst.APP_IOS_TIPS.equals(config.getConfigKey())) {
                    appVersionDto.setIosTips(config.getConfigValue());
                }
                if (SystemConst.APP_ANDROID_VERSION.equals(config.getConfigKey())) {
                    appVersionDto.setAndroidVersion(config.getConfigValue());
                }
                if (SystemConst.APP_ANDROID_TIPS.equals(config.getConfigKey())) {
                    appVersionDto.setAndroidTips(config.getConfigValue());
                }
                if (SystemConst.APP_APK.equals(config.getConfigKey())) {
                    appVersionDto.setApk(config.getConfigValue());
                }
                if (SystemConst.APP_ANDROID_FORCE.equals(config.getConfigKey())) {
                    appVersionDto.setAndroidForce(Integer.parseInt(config.getConfigValue()));
                }
                if (SystemConst.APP_IOS_FORCE.equals(config.getConfigKey())) {
                    appVersionDto.setIosForce(Integer.parseInt(config.getConfigValue()));
                }
                if (SystemConst.APP_PHONE.equals(config.getConfigKey())) {
                    appVersionDto.setPhone(config.getConfigValue());
                }
                if (SystemConst.APP_WECHAT.equals(config.getConfigKey())) {
                    appVersionDto.setWechat(Integer.parseInt(config.getConfigValue()));
                }
                if (SystemConst.APP_MAPS.equals(config.getConfigKey())) {
                    appVersionDto.setMaps(Integer.parseInt(config.getConfigValue()));
                }
            } catch (Exception e) {
                log.error("系统参数配置错误：" + config.getConfigKey());
            }
        }
        return R.ok(appVersionDto);
    }

    /**
     * 密码登录
     *
     * @return
     */
    @PostMapping("/loginByPassword")
    public R<SysBizUser> loginByPassword(@RequestBody @Validated PasswordLoginDto passwordLoginDto) {
        String phoneNumber = passwordLoginDto.getPhoneNumber();
        String lockKey = "LOGIN:PHONE:" + phoneNumber;
        // 尝试获取锁
        Boolean isLocked = redisTemplate.opsForValue().setIfAbsent(lockKey, "locked", LOCK_EXPIRE_TIME, TimeUnit.SECONDS);
        if (Boolean.FALSE.equals(isLocked)) {
            return R.fail("正在加载，请勿重复点击");
        }
        try {
        SysBizUser user = sysBizUserService.getOne(new LambdaQueryWrapper<SysBizUser>()
                .eq(SysBizUser::getUserPhone, passwordLoginDto.getPhoneNumber())
                .eq(SysBizUser::getDeleted, OrderDeleteEnum.NOT_DELETE.getKey()));
        if (user == null || StringUtils.isBlank(user.getPassword())) {
            return R.fail("用户名或密码错误");
        }
        SysBizUser sysBizUser = sysBizUserService.loginByPassword(passwordLoginDto, user);
        return R.ok(sysBizUser);
        } finally {
            // 释放锁
            redisTemplate.delete(lockKey);
        }
    }

    /**
     * 发送忘记密码验证码
     *
     * @return
     */
    @PostMapping("/verificationCodeByPassword/{phoneNum}")
    public R<String> verificationCodeByPassword(@PathVariable("phoneNum") String phoneNum) throws Exception {
        if (StringUtils.isBlank(phoneNum)) {
            return R.fail("登录手机号不能为空");
        }
        String code = String.format("%6d", 100000 + new Random().nextInt(900000));
        if (cacheService.exists(UPDATE_PASSWORD_CODE + phoneNum)) {
            cacheService.remove(phoneNum);
        }
        if (cacheService.setNX(UPDATE_PASSWORD_CODE + phoneNum, code, 60 * 5)) {
            smsManager.sendCode(code, phoneNum);
        }
        return R.ok();
    }

    /**
     * 忘记密码修改密码
     *
     * @return
     */
    @PostMapping("/updatePassword")
    public R<String> updatePassword(@RequestBody @Validated UpdatePasswordDto updatePasswordDto) {
        if (!cacheService.exists(UPDATE_PASSWORD_CODE + updatePasswordDto.getPhoneNumber()) || !updatePasswordDto.getVerificationCode().equals(cacheService.get(UPDATE_PASSWORD_CODE + updatePasswordDto.getPhoneNumber()) + "")) {
            return R.fail("验证码错误");
        }
        SysBizUser sysBizUser = sysBizUserService.getOne(new LambdaQueryWrapper<SysBizUser>().eq(SysBizUser::getUserPhone, updatePasswordDto.getPhoneNumber()).eq(SysBizUser::getDeleted, OrderDeleteEnum.NOT_DELETE.getKey()));
        if (sysBizUser == null) {
            return R.fail("用户不存在");
        }
        sysBizUserService.updatePassword(updatePasswordDto, sysBizUser);
        return R.ok();
    }

}
